Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Unit Tests For SSL Operations #1845

Open
wants to merge 17 commits into
base: BABEL_3_X_DEV
Choose a base branch
from

Conversation

vikashprajapati-cell
Copy link
Contributor

@vikashprajapati-cell vikashprajapati-cell commented Sep 15, 2023

Description

SSL (Secure Sockets Layer) is a cryptographic protocol used to establish secure connections between clients and servers. Testing SSL functionality ensures the secure transmission of data between clients and servers. Adding tests for SSL involves evaluating how the Babelfish codebase handles SSL connections.
We are keen on conducting thorough unit testing of the SslHandshake process that occurs during the prelogin stage. Our unit testing approach involves meticulously examining each step of the handshake, simulating various scenarios, and verifying the correct implementation of the SSL handshake. Through this comprehensive testing, we aim to identify any potential vulnerabilities that may exist.

  • Note-
    To execute SSL-related tests, it is essential to enable the SSL flag during the build process using the --with-openssl command. This ensures that the necessary components for SSL testing are included. In the event that the SSL flag is not enabled, only non-SSL tests will be executed.

Authored-by: Vikash Prajapati [email protected]
Signed-off-by: Vikash Prajapati [email protected]

Test Scenarios Covered

jdbc_testdb=# CREATE EXTENSION IF NOT EXISTS babelfishpg_unit;
CREATE EXTENSION
jdbc_testdb=# select * from babelfishpg_unit.babelfishpg_unit_run_tests();
                  test_name                  | status |                   message                   | runtime | enabled 
---------------------------------------------+--------+---------------------------------------------+---------+---------
 GreaterThanOrEqualToCheck_INT4_FIXEDDECIMAL | pass   |                                             |       6 | enabled
 LesserThanOrEqualToCheck_INT4_FIXEDDECIMAL  | pass   |                                             |       1 | enabled
 NotEqualToCheck_INT4_FIXEDDECIMAL           | pass   |                                             |       1 | enabled
 EqualToCheck_INT4_FIXEDDECIMAL              | pass   |                                             |       2 | enabled
 LesserThanCheck_INT4_FIXEDDECIMAL           | pass   |                                             |       1 | enabled
 Comparison_INT4_FIXEDDECIMAL                | pass   |                                             |       3 | enabled
 FIXEDDECIMALUM                              | pass   | fixeddecimal out of range                   |      11 | enabled
 GreaterThanOrEqualToCheck_FIXEDDECIMAL_INT2 | pass   |                                             |       1 | enabled
 LesserThanOrEqualToCheck_FIXEDDECIMAL_INT2  | pass   |                                             |       1 | enabled
 GreaterThanCheck_FIXEDDECIMAL_INT2          | pass   |                                             |       1 | enabled
 NotEqualToCheck_FIXEDDECIMAL_INT2           | pass   |                                             |       1 | enabled
 Comparison_FIXEDDECIMAL_INT2                | pass   |                                             |       2 | enabled
 Testing_SSL_HANDSHAKE_READ                  | pass   |                                             |      21 | enabled
 TestingOverSize_SSL_HANDSHAKE_READ          | pass   |  SSL packet expand more than one TDS packet |      52 | enabled
 TestingPacketType_SSL_HANDSHAKE_READ        | pass   |                                             |       6 | enabled
 Testing_SSL_HANDSHAKE_WRITE                 | pass   |                                             |       4 | enabled
 TestingSizeCheck_SSL_HANDSHAKE_WRITE        | pass   |  There is nothing to write                  |       1 | enabled
(17 rows)

Check List

  • Commits are signed per the DCO using --signoff

By submitting this pull request, I confirm that my contribution is under the terms of the Apache 2.0 and PostgreSQL licenses, and grant any person obtaining a copy of the contribution permission to relicense all or a portion of my contribution to the PostgreSQL License solely to contribute all or a portion of my contribution to the PostgreSQL open source project.

For more information on following Developer Certificate of Origin and signing off your commits, please check here.

Signed-off-by: Vikash Prajapati <[email protected]>
contrib/babelfishpg_unit/test_ssl_read.c Outdated Show resolved Hide resolved
contrib/babelfishpg_unit/test_ssl_write.c Outdated Show resolved Hide resolved
contrib/babelfishpg_unit/test_ssl_write.c Outdated Show resolved Hide resolved
contrib/babelfishpg_unit/test_ssl_read.c Outdated Show resolved Hide resolved
contrib/babelfishpg_unit/test_ssl_read.c Outdated Show resolved Hide resolved
Signed-off-by: Vikash Prajapati <[email protected]>
Copy link
Contributor

@thephantomthief thephantomthief left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be running these new tests as part of github actions. Currently I think that is not happening

Signed-off-by: Vikash Prajapati <[email protected]>

obtained = test_ssl_handshake_read(h, buf, expected, mock_socket_read, ReadPointer);

size_buf = strlen(buf);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strlen only works in string is null terminated

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in the latest commit.

*/
if(expected == obtained)
{
TEST_ASSERT_TESTCASE(*((unsigned char*)expected_str) == *((unsigned char*)buf), testResult);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we only comparing first character?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in the latest commit with complete string comparision.

snprintf(expected_str, MAX_TEST_MESSAGE_LENGTH, "%d", expected);
snprintf(obtained_str, MAX_TEST_MESSAGE_LENGTH, "%d", obtained);

TEST_ASSERT_TESTCASE(expected != obtained, testResult);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not clear, what do we expect here that multi packet message should be handled properly, if yes why results should not match

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the logic in the latest commit.

*/

int res;
tds_secure_raw_write = mock_socket_write;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we reset it after the unit testing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, have updated in the next revision.


int res;
tds_secure_raw_write = mock_socket_write;
unit_testing = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if there is an error during testing and unit_testing remains true? I think not an issue in current set of tests but could be a problem later

Copy link
Contributor Author

@vikashprajapati-cell vikashprajapati-cell Oct 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Handled this using PG_TRY() and PG_FINALLY() block in the latest commit.

(errcode(ERRCODE_ADMIN_SHUTDOWN),
errmsg("terminating connection due to unexpected ssl packet header")));

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unnecessary white spaces

tds_secure_raw_read = mock_socket_read;
unit_testing = true;
pkt_bytes_read = ReadPointer;
PG_TRY();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation

}
PG_END_TRY();

tds_secure_raw_read = secure_raw_read;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

put this also in finally block

tds_secure_raw_write = mock_socket_write;
unit_testing = true;

PG_TRY();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation, also put write API reset in finally block


obtained = test_ssl_handshake_read(h, buf, expected, mock_socket_read, ReadPointer);

null_terminated_expected = strdup(expected_str);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why these copies? we can compare expected_str and buf directly. However, is buf guaranteed to be null terminated?

memcpy(obtained_str, buf, obtained);
obtained_next = test_ssl_handshake_read(h, buf, expected - obtained, mock_socket_read, ReadPointer);
memcpy(obtained_str + obtained, buf, obtained_next);
null_terminated_expected = strdup(expected_str);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again why this copy? also if obtained_str is not null terminated how will strdup will work. You just need to put at '\0' at the end

TestResult* testResult = palloc0(sizeof(TestResult));
testResult->result = true;

prelogin_request = strdup("1201000F0000010011A25E4571");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you explain the message format? how does it force two packet reads?


h = BIO_new(BIO_s_mem());

prelogin = malloc(strlen(buf)/2 + 8);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we writing buf/2 rather than buf?

snprintf(obtained_str, MAX_TEST_MESSAGE_LENGTH, "%d", obtained);

TEST_ASSERT_TESTCASE(expected == obtained, testResult);
if(testResult->result == true)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why both if/else cases?

expected = -1;
obtained = test_ssl_handshake_write(h, buf, expected, mock_socket_write);

snprintf(expected_str, MAX_TEST_MESSAGE_LENGTH, "%d", expected);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are not used anywhere?

Vikash Prajapati added 7 commits October 9, 2023 04:16
}
PG_END_TRY();

return res;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation

TestResult* testResult = palloc0(sizeof(TestResult));
testResult->result = true;

prelogin_request = strdup("1201000B00000100115461A23E");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again, why are we manipulating length here?


obtained_str = (char *)malloc(obtained + 1);
strncpy(obtained_str, buf, obtained);
obtained_str[obtained] = '\0';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what are we achieving with this comparison? both expected and obtained strings are copy of buf only. We should compared expected against prelogin string where mock socket write happens (after skipping header part)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants